home *** CD-ROM | disk | FTP | other *** search
- /* Internet FTP Server server machine - see RFC 959
- * Copyright 1991 Phil Karn, KA9Q
- *
- * Mods by KO4KS
- */
- #include <stdio.h>
- #include <ctype.h>
- #include <time.h>
- #ifdef __TURBOC__
- #include <io.h>
- #include <dir.h>
- #endif
- #include <sys/stat.h>
- #include "global.h"
- #include "config.h"
- #include "mbuf.h"
- #include "socket.h"
- #include "ftp.h"
- #include "ftpserv.h"
- #include "proc.h"
- #include "dirutil.h"
- #include "files.h"
- #include "commands.h"
- #include "session.h"
- #include "md5.h"
- #include "smtp.h"
- #ifdef CALLSERVER
- #include <string.h>
- /* CD-ROM code by Fred Peachman KB7YW */
- extern char *CDROM; /* buckbook.c: defines CDROM drive letter e.g. "s:" */
- #endif /* #ifdef CALLSERVER */
- #ifdef LZW
- #include "lzw.h"
- #endif
-
- static void ftpserv __ARGS((int s,void *unused,void *p));
- static int pport __ARGS((struct sockaddr_in *sock,char *arg));
- static void ftplogin __ARGS((struct ftpserv *ftp,char *pass));
- static int sendit __ARGS((struct ftpserv *ftp,char *command,char *file));
- static int recvit __ARGS((struct ftpserv *ftp,char *command,char *file));
- static void sendmsgfile __ARGS((int s,int num,char *buf,int size,FILE *fp));
- int doftptdisc __ARGS((int argc, char *argv[], void *p));
- extern char *addroot __ARGS((char *root, char *name));
- extern int dir_ok __ARGS((char * newpath,struct cur_dirs * dirs));
- extern char * defpath __ARGS((struct cur_dirs *curdirs, char *path));
-
- /* Command table */
- static char *commands[] = {
- "user",
- "acct",
- "pass",
- "type",
- "list",
- "cwd",
- "dele",
- "name",
- "quit",
- "retr",
- "stor",
- "port",
- "nlst",
- "pwd",
- "xpwd", /* For compatibility with 4.2BSD */
- "mkd ",
- "xmkd", /* For compatibility with 4.2BSD */
- "xrmd", /* For compatibility with 4.2BSD */
- "rmd ",
- "stru",
- "mode",
- "syst",
- "xmd5",
- "rsme", /* Added by IW0CNB, for resuming interrupted trasnfers */
- "rput",
- #ifdef LZW
- "xlzw",
- #endif
- "rnfr",
- "rnto",
- "cdup",
- "appe",
- NULLCHAR
- };
-
- /* Response messages */
- #ifdef ITT
- static char banner[] = "220 %s, ITT-TMNG FTP version %s\n";
- #else
- static char banner[] = "220 %s, KA9Q-NOS FTP version %s\n";
- #endif
- static char banner1[] = "230- Ready on %s";
- static char badcmd[] = "500 Unknown command\n";
- static char binwarn[] = "100 Warning: type is ASCII and %s appears to be binary\n";
- static char unsupp[] = "500 Unsupported command or option\n";
- static char givepass[] = "331 Enter PASS command\n";
- static char anonokay[] = "331 Anonymous access, give email address as password\n";
- static char challenge[] = "399 PASS challenge : %016lx\n";
- static char logged[] = "230 Logged in\n";
- static char loggeda[] = "230 Logged in as anonymous, restrictions apply\n";
- static char typeok[] = "200 Type %s OK\n";
- static char only8[] = "501 Only logical bytesize 8 supported\n";
- static char deleok[] = "250 File deleted\n";
- static char mkdok[] = "200 MKD ok\n";
- static char delefail[] = "550 Delete failed: %s\n";
- static char pwdmsg[] = "257 \"%s\" is current directory\n";
- static char badtype[] = "501 Unknown type \"%s\"\n";
- static char badport[] = "501 Bad port syntax\n";
- static char unimp[] = "502 Command not yet implemented\n";
- static char bye[] = "221 Goodbye!\n";
- static char nodir[] = "553 Can't read directory \"%s\": %s\n";
- static char cantopen[] = "550 Can't read file \"%s\": %s\n";
- static char sending[] = "150 Opening data connection for %s %s %s\n"; /*N1BEE*/
- static char cantmake[] = "553 Can't create \"%s\": %s\n";
- static char writerr[] = "552 Write error: %s\n";
- static char portok[] = "200 Port command okay\n";
- static char rxok[] = "226 File received OK\n";
- static char txok[] = "226 File sent OK\n";
- static char noperm[] = "550 Permission denied\n";
- static char noconn[] = "425 Data connection reset\n";
- static char badcheck[] = "425 Bad checksum\n";
- static char lowmem[] = "421 System overloaded, try again later\n";
- static char notlog[] = "530 Please log in with USER and PASS\n";
- static char userfirst[] = "503 Login with USER first.\n";
- static char okay[] = "200 Ok\n";
- static char syst[] = "215 %s Type: L%d Version: %s\n";
- static char pendingto[] = "350 Rename awaiting new name.\n";
- static char badseq[] = "503 No prior RNFR received - RNTO ignored\n";
- static char norename[] = "550 Can't rename: %s\n";
-
- int Sftp = -1; /* Prototype socket for service */
- int FtpUsers = 0;
-
- #ifdef FTPTDISC
- int32 Ftptdiscinit = 0;
-
- /* Set ftp redundancy timer */
- int
- doftptdisc(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setlong(&Ftptdiscinit,"Ftp redundancy timer (sec)",argc,argv);
- }
-
- static void
- ftp_redundant(ftp)
- struct ftpserv *ftp;
- {
- /* Clean up */
- shutdown(ftp->control,2);
- close_s(ftp->control);
- if(ftp->data != -1){
- shutdown(ftp->data,2);
- close_s(ftp->data);
- ftp->data = -1;
- }
- return;
- }
- #endif
-
- /* Start up FTP service */
- int
- ftpstart(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return (installserver (argc, argv, &Sftp, "FTP listener", IPPORT_FTP,
- "ftpserv", ftpserv, 2048, NULL));
- }
-
- static void sendmsgfile(s, num, buf, size, fp)
- int s, num;
- char *buf;
- int size;
- FILE *fp;
- {
-
- while(fgets(buf,size,fp)) {
- rip(buf);
- usprintf(s,"%d- %s\n",num,buf);
- }
- }
-
- static int
- isanonymous (name)
- char *name;
- {
- FILE *fp;
- int retval = 1;
- char buf[128], *cp;
-
- if((fp = fopen(Userfile,READ_TEXT)) != NULLFILE) {
- while ( fgets(buf,128,fp) != NULLCHAR ){
- if((cp = strpbrk(buf," \t")) == NULLCHAR)
- /* Bogus entry */
- continue;
- *cp++ = '\0';
-
- if(!stricmp(name,buf)) {
- retval = 0;
- break; /* Found user */
- }
- }
- fclose (fp);
- }
- return (retval);
- }
-
-
- static void
- ftpserv(s,unused,p)
- int s; /* Socket with user connection */
- void *unused;
- void *p;
- {
- struct ftpserv ftp;
- struct stat cwdstat;
- char **cmdp,buf[512],*arg,*cp,*cp1,*file,*mode;
- long t;
- int cnt,i;
- struct sockaddr_in socket;
- struct cur_dirs dirs;
- char *rnfrom = NULLCHAR;
- FILE *fpm;
-
- sockmode(s,SOCK_ASCII);
- memset((char *)&ftp,0,sizeof(ftp)); /* Start with clear slate */
- ftp.data = -1;
-
- sockowner(s,Curproc); /* We own it now */
- ftp.control = s;
- /* Set default data port */
- i = SOCKSIZE;
- getpeername(s,(char *)&socket,&i);
- socket.sin_port = IPPORT_FTPD;
- ASSIGN(ftp.port,socket);
-
- #ifdef FTPTDISC
- /* Set the timeout timer - WG7J */
- set_timer(&ftp.tdisc,Ftptdiscinit * 1000L);
- ftp.tdisc.func = ftp_redundant;
- ftp.tdisc.arg = &ftp;
- start_timer(&ftp.tdisc);
- #endif
-
- log(s,"open FTP");
- FtpUsers++;
- init_dirs(&dirs);
- ftp.curdirs = &dirs;
- usprintf(s,banner,Hostname,Version);
- time(&t);
- cp = ctime(&t);
- #ifdef notdef
- if((cp1 = strchr(cp,'\n')) != NULLCHAR)
- *cp1 = '\0';
- #endif
-
- /* Command interpreting loop */
- loop:
- if((cnt = recvline(s,buf,sizeof(buf))) == -1){
- /* He closed on us */
- goto finish;
- }
- #ifdef FTPTDISC
- /* Reset the timeout timer - WG7J */
- start_timer(&ftp.tdisc);
- #endif
- if(cnt == 0){
- /* Can't be a legal FTP command */
- usprintf(ftp.control,badcmd);
- goto loop;
- }
- rip(buf);
- /* Translate first word to lower case */
- for(cp = buf;*cp != ' ' && *cp != '\0';cp++)
- *cp = tolower(*cp);
- /* Find command in table; if not present, return syntax error */
- for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
- if(strnicmp(*cmdp,buf,strlen(*cmdp)) == 0)
- break;
- if(*cmdp == NULLCHAR){
- usprintf(ftp.control,badcmd);
- goto loop;
- }
- /* Allow only USER, PASS and QUIT before logging in */
- if(ftp.path == NULLCHAR){
- switch(cmdp-commands){
- case USER_CMD:
- case PASS_CMD:
- case QUIT_CMD:
- break;
- default:
- usprintf(ftp.control,notlog);
- goto loop;
- }
- }
- arg = &buf[strlen(*cmdp)];
- while(*arg == ' ')
- arg++;
-
- /* Execute specific command */
- switch(cmdp-commands){
- case USER_CMD:
- free(ftp.username);
- ftp.username = strdup(arg);
- /* if(sp_user(ftp.username)) {
- time(&ftp.ttim);
- usprintf(ftp.control,challenge,ftp.ttim);
- }
- else
- */
- if (isanonymous (arg))
- usprintf(ftp.control,anonokay);
- else
- usprintf(ftp.control,givepass);
- break;
- case TYPE_CMD:
- switch(arg[0]){
- case 'A':
- case 'a': /* Ascii */
- ftp.type = ASCII_TYPE;
- usprintf(ftp.control,typeok,arg);
- break;
- case 'l':
- case 'L':
- while(*arg != ' ' && *arg != '\0')
- arg++;
- if(*arg == '\0' || *++arg != '8'){
- usprintf(ftp.control,only8);
- break;
- }
- ftp.type = LOGICAL_TYPE;
- ftp.logbsize = 8;
- usprintf(ftp.control,typeok,arg);
- break;
- case 'B':
- case 'b': /* Binary */
- case 'I':
- case 'i': /* Image */
- ftp.type = IMAGE_TYPE;
- usprintf(ftp.control,typeok,arg);
- break;
- default: /* Invalid */
- usprintf(ftp.control,badtype,arg);
- break;
- }
- break;
- case QUIT_CMD:
- usprintf(ftp.control,bye);
- goto finish;
- case RNFR_CMD:
- file = addroot(ftp.curdirs->dir,arg);
- if(!permcheck(ftp.path,ftp.perms,RNFR_CMD,file))
- usprintf(ftp.control,noperm);
- else if (access (file, 6))
- usprintf(ftp.control,cantopen,file,sys_errlist[errno]);
- else {
- usprintf(ftp.control,pendingto);
- rnfrom = strdup (file);
- }
- free (file);
- break;
- case RNTO_CMD:
- file = addroot(ftp.curdirs->dir,arg);
- if(rnfrom == NULLCHAR)
- usprintf(ftp.control,badseq);
- else {
- if(!permcheck(ftp.path,ftp.perms,RNTO_CMD,file))
- usprintf(ftp.control,noperm);
- else {
- if(rename(rnfrom,file) == -1)
- usprintf(ftp.control,norename,sys_errlist[errno]);
- else
- usprintf(ftp.control,okay);
- }
- free (rnfrom);
- rnfrom = NULLCHAR;
- }
- free (file);
- break;
- case RETR_CMD:
- case RSME_CMD:
- file = addroot(ftp.curdirs->dir,arg);
- switch(ftp.type){
- case IMAGE_TYPE:
- case LOGICAL_TYPE:
- mode = READ_BINARY;
- break;
- case ASCII_TYPE:
- mode = READ_TEXT;
- break;
- }
- if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
- usprintf(ftp.control,noperm);
- } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
- usprintf(ftp.control,cantopen,file,sys_errlist[errno]);
- } else {
- if((cmdp-commands) == RSME_CMD) {
- log(ftp.control,"RSME %s",file);
- if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
- usprintf(ftp.control,binwarn,file);
- }
- sendit(&ftp,"RSME",file);
- } else {
- log(ftp.control,"RETR %s",file);
- if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
- usprintf(ftp.control,binwarn,file);
- }
- sendit(&ftp,"RETR",file);
- }
- }
- free(file);
- break;
- case STOR_CMD:
- cp = "STOR";
- goto store2;
- case APPE_CMD:
- cp = "APPE";
- goto store2;
- case RPUT_CMD:
- cp = "RPUT";
- store2: file = addroot(ftp.curdirs->dir,arg);
- switch(ftp.type){
- case IMAGE_TYPE:
- case LOGICAL_TYPE:
- if(cmdp-commands != STOR_CMD)
- mode = APPEND_BINARY;
- else
- mode = WRITE_BINARY;
- break;
- case ASCII_TYPE:
- if(cmdp-commands != STOR_CMD)
- mode = APPEND_TEXT;
- else
- mode = WRITE_TEXT;
- break;
- }
- if(!permcheck(ftp.path,ftp.perms,cmdp-commands,file)){
- usprintf(ftp.control,noperm);
- } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
- usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
- } else {
- log(ftp.control,"%s %s",cp, file);
- recvit(&ftp,cp,file);
- }
- free(file);
- break;
- case PORT_CMD:
- if(pport(&ftp.port,arg) == -1){
- usprintf(ftp.control,badport);
- } else {
- usprintf(ftp.control,portok);
- }
- break;
- #ifndef CPM
- case LIST_CMD:
- case NLST_CMD:
- file = addroot(ftp.curdirs->dir,defpath (ftp.curdirs, arg));
- if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file))
- usprintf(ftp.control,noperm);
- else {
- cp = Command->curdirs->dir;
- Command->curdirs->dir = ftp.curdirs->dir;
- if((ftp.fp = dir(file,((cmdp-commands) == LIST_CMD) ? 1 : 0)) == NULLFILE)
- usprintf(ftp.control,nodir,file,sys_errlist[errno]);
- else
- sendit(&ftp,((cmdp-commands) == LIST_CMD) ? "LIST" : "NLST",file);
- Command->curdirs->dir = cp;
- }
- free(file);
- break;
- case CDUP_CMD:
- sprintf (arg, ".."); /* and fall through */
- case CWD_CMD:
- cwdentry:
- #ifdef old_CALLSERVER
- /* if the requested path contains the CROM drive letter: */
- if (CDROM != NULLCHAR && strnicmp(CDROM, arg, 2) == 0) {
- if (strchr(arg, '/') == NULLCHAR) {
- file = (char *)malloc(strlen(arg) + 2);
- sprintf(file,"%s/", arg);
- } else file = strdup(arg);
- if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
- usprintf(ftp.control,noperm);
- free(file);
- /* Don'tcha just LOVE %%$#@!! MS-DOS? - which is what we are running */
- } else if(file[2] == '/' || access(file,0) == 0){
- /* Succeeded, record in control block */
- free(ftp.cd);
- ftp.cd = file;
- usprintf(ftp.control,"You may return to your default drive & directory by entering:\n\t\t\"cd %s\"\n\n", ftp.path);
- usprintf(ftp.control,pwdmsg,file);
- } else {
- /* Failed, don't change anything */
- usprintf(ftp.control,nodir,file,sys_errlist[errno]);
- free(file);
- }
- break;
- }
- /* requested path does not contain CDROM drive letter: */
- /* if current dir is in CDROM - and a "off-root" is requested:
- go back to default path. */
- if ((CDROM != NULLCHAR && strnicmp(ftp.cd, CDROM, 2) == 0) && (arg[0] == '/')) {
- free(ftp.cd);
- ftp.cd = strdup(ftp.path); /* go back to default path */
- }
- #endif /* #ifdef CALLSERVER */
- file = addroot(ftp.curdirs->dir,arg);
- if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file))
- usprintf(ftp.control,noperm);
- else if (dir_ok(file,ftp.curdirs)) {
- /* Succeeded */
- /* If exists, send the contents of 'desc.ftp' in the new
- * directory...
- */
- strcpy(buf,file);
- if((fpm = fopen(strcat(buf,"/desc.ftp"),"r")) != NULL) {
- sendmsgfile(ftp.control,257,buf,sizeof(buf),fpm);
- fclose(fpm);
- }
-
- usprintf(ftp.control,pwdmsg,ftp.curdirs->dir);
- } else
- /* Failed, nothing changed */
- usprintf(ftp.control,nodir,arg,sys_errlist[errno]);
- free(file);
- break;
- case XPWD_CMD:
- case PWD_CMD:
- usprintf(ftp.control,pwdmsg,ftp.curdirs->dir);
- break;
- #else
- case LIST_CMD:
- case NLST_CMD:
- case CWD_CMD:
- case XPWD_CMD:
- case PWD_CMD:
- #endif
- case ACCT_CMD:
- usprintf(ftp.control,unimp);
- break;
- case DELE_CMD:
- file = addroot(ftp.curdirs->dir,arg);
- if(!permcheck(ftp.path,ftp.perms,DELE_CMD,file)){
- usprintf(ftp.control,noperm);
- } else if(unlink(file) == 0){
- log(ftp.control,"DELE %s",file);
- usprintf(ftp.control,deleok);
- } else {
- usprintf(ftp.control,delefail,sys_errlist[errno]);
- }
- free(file);
- break;
- case PASS_CMD:
- if(ftp.username == NULLCHAR)
- usprintf(ftp.control,userfirst);
- else
- ftplogin(&ftp,arg);
- break;
- #ifndef CPM
- case XMKD_CMD:
- case MKD_CMD:
- file = addroot(ftp.curdirs->dir,arg);
- if(!permcheck(ftp.path,ftp.perms,MKD_CMD,file)){
- usprintf(ftp.control,noperm);
- #ifdef UNIX
- } else if(mkdir(file,0777) == 0){
- #else
- } else if(mkdir(file) == 0){
- #endif
- log(ftp.control,"MKD %s",file);
- usprintf(ftp.control,mkdok);
- } else {
- usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
- }
- free(file);
- break;
- case XRMD_CMD:
- case RMD_CMD:
- file = addroot(ftp.curdirs->dir,arg);
- if(!permcheck(ftp.path,ftp.perms,RMD_CMD,file)){
- usprintf(ftp.control,noperm);
- } else if(rmdir(file) == 0){
- log(ftp.control,"RMD %s",file);
- usprintf(ftp.control,deleok);
- } else {
- usprintf(ftp.control,delefail,sys_errlist[errno]);
- }
- free(file);
- break;
- case STRU_CMD:
- if(tolower(arg[0]) != 'f')
- usprintf(ftp.control,unsupp);
- else
- usprintf(ftp.control,okay);
- break;
- case MODE_CMD:
- if(tolower(arg[0]) != 's')
- usprintf(ftp.control,unsupp);
- else
- usprintf(ftp.control,okay);
- break;
- case SYST_CMD:
- usprintf(ftp.control,syst,System,NBBY,Version);
- break;
- case XMD5_CMD:
- file = addroot(ftp.curdirs->dir,arg);
- switch(ftp.type){
- case IMAGE_TYPE:
- case LOGICAL_TYPE:
- mode = READ_BINARY;
- break;
- case ASCII_TYPE:
- mode = READ_TEXT;
- break;
- }
- if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
- usprintf(ftp.control,noperm);
- } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
- usprintf(ftp.control,cantopen,file,sys_errlist[errno]);
- } else {
- char hash[16];
-
- log(ftp.control,"XMD5 %s",file);
- if(ftp.type == ASCII_TYPE && isbinary(ftp.fp))
- usprintf(ftp.control,binwarn,file);
-
- md5hash(ftp.fp,hash,ftp.type == ASCII_TYPE);
- fclose(ftp.fp);
- ftp.fp = NULLFILE;
- usprintf(ftp.control,"200 ");
- for(i=0;i<16;i++)
- usprintf(ftp.control,"%02x",hash[i] & 0xff);
- usprintf(ftp.control," %s\n",file);
- }
- free(file);
- break;
- #ifdef LZW
- case XLZW_CMD:
- if (ftp.lzw)
- usprintf (ftp.control, "550 Already using LZW compression\n");
- else {
- int lzwbits, lzwmode;
- usprintf (ftp.control, okay);
- sscanf(&buf[5],"%d %d",&ftp.lzwbits,&ftp.lzwmode);
- /* lzwinit (ftp.control, ftp.lzwbits, ftp.lzwmode); */
- ftp.lzw = 1;
- }
- break;
- #endif
- }
- #endif
- goto loop;
- finish:
-
- #ifdef FTPTDISC
- stop_timer(&ftp.tdisc);
- #endif
-
- log(ftp.control,"close FTP from '%s'", ftp.username);
- FtpUsers--;
- /* Clean up */
- close_s(ftp.control);
- if(ftp.data != -1)
- close_s(ftp.data);
- if(ftp.fp != NULLFILE)
- fclose(ftp.fp);
- free(ftp.username);
- free(ftp.path);
- free_dirs(&dirs);
- free(rnfrom);
- }
-
- /* Shut down FTP server */
- int
- ftp0(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return (deleteserver (&Sftp));
- }
- static
- int
- pport(sock,arg)
- struct sockaddr_in *sock;
- char *arg;
- {
- int32 n;
- int i;
-
- n = 0;
- for(i=0;i<4;i++){
- n = atoi(arg) + (n << 8);
- if((arg = strchr(arg,',')) == NULLCHAR)
- return -1;
- arg++;
- }
- sock->sin_addr.s_addr = n;
- n = atoi(arg);
- if((arg = strchr(arg,',')) == NULLCHAR)
- return -1;
- arg++;
- n = atoi(arg) + (n << 8);
- sock->sin_port = n;
- return 0;
- }
-
- /* Attempt to log in the user whose name is in ftp->username and password
- * in pass
- */
- static void
- ftplogin(ftp,pass)
- struct ftpserv *ftp;
- char *pass;
- {
- char *path, buf[128], *cp;
- char *p;
- long t;
- FILE *fp;
- int anony = 0;
-
- path = mallocw(200);
- if((ftp->perms = userlogin(ftp->username,pass,&path,200,&anony))
- == -1){
- log(ftp->control,"FTP login refused - '%s'", ftp->username);
- usprintf(ftp->control,noperm);
- free(path);
- return;
- }
- /* Set up current directory and path prefix */
- #if defined(AMIGAGONE)
- ftp->path = strdup(ftp->cd);
- free(path);
- #else
- ftp->path = path;
- #endif
-
- {
- FILE *out;
- sprintf(buf,"%s/ftp.log",Spool);
- if((out = fopen(buf,APPEND_TEXT)) != NULLFILE) {
- time_t t;
- time(&t);
- fprintf (out, "FTP from %s (%s) on %s", ftp->username, pass, ptime(&t));
- fclose (out);
- }
- }
-
- time(&t);
- cp = ctime(&t);
- usprintf(ftp->control,banner1,cp);
-
- /* everyone gets the ftpmotd file, if it exists */
- if((fp = fopen(Ftpmotd,"r")) != NULL) {
- sendmsgfile(ftp->control,230,buf,sizeof(buf),fp);
- fclose(fp);
- }
-
- /* if there is a message.ftp file in the login dir, send it too */
- sprintf(buf,"%s%s%s", path, (path[strlen(path)-1] == '/') ? "" : "/", "message.ftp");
- if((fp = fopen(buf,"r")) != NULL) {
- sendmsgfile(ftp->control,230,buf,sizeof(buf),fp);
- fclose(fp);
- }
-
- path = strdup (ftp->path);
- if ((p = strpbrk (path, "=;")) != NULLCHAR)
- *p = 0;
- if (dir_ok(path,ftp->curdirs)) {
- /* Succeeded */
- /* If exists, send the contents of 'desc.ftp' in the new directory... */
- sprintf (buf, "%s/desc.ftp", path);
- if((fp = fopen(buf,"r")) != NULL) {
- sendmsgfile(ftp->control,230,buf,sizeof(buf),fp);
- fclose(fp);
- }
- }
-
- free (path);
- if(!anony){
- usprintf(ftp->control,logged);
- log(ftp->control,"FTP login - '%s'",ftp->username);
- } else {
- usprintf(ftp->control,loggeda);
- log(ftp->control,"FTP anonymous login - '%s' (%s)",ftp->username,pass);
- }
- usflush (ftp->control);
- pwait (NULL);
- }
-
- #ifdef MSDOS
- /* Illegal characters in a DOS filename */
- static char badchars[] = "\"[]|<>+=;,";
- #endif
-
- /* Return 1 if the file operation is allowed, 0 otherwise */
- int
- permcheck(path,perms,op,file)
- char *path;
- int perms;
- int op;
- char *file;
- {
- char *cp, *cp1;
- int newperms;
-
- if(file == NULLCHAR || path == NULLCHAR)
- return 0; /* Probably hasn't logged in yet */
-
- /* To get to the CDROM - EVERYBODY gets read privs, regardless of what
- /ftpusers has to say about it!!! - kb7yw */
-
- #ifdef CALLSERVER
- if (CDROM != NULLCHAR && strnicmp(file, CDROM ,2) == 0) {
- /* Check for characters illegal in MS-DOS file names */
- for(cp = badchars;*cp != '\0';cp++){
- if(strchr(&file[2],*cp) != NULLCHAR)
- return 0;
- }
-
- switch(op){ /* What to do when the user is on the cd-rom drive */
- case RETR_CMD: /* Everybody gets read privs regardless of ftpusers */
- /* User has permission to read files */
- return 1;
- case DELE_CMD:
- case RMD_CMD:
- /* User must not have permission to (over)write files */
- case STOR_CMD:
- case MKD_CMD:
- /* User must NOT have permission to (over)write files
- */
- return 0;
- } /* switch(op) */
- } /* if strncmp(.... */
- #endif /* #ifdef CALLSERVER */
- #ifndef MAC
- /* The target file must be under the user's allowed search path */
- /* We let them specify multiple paths using path;path... -russ */
- for(cp = path;;cp = cp1+1){
- char *cp2;
- newperms = perms;
- if((cp1 = strchr(cp,';')) == NULLCHAR) cp1 = strchr(cp,'\0');
- if (((cp2 = strchr(cp, '=')) == NULLCHAR) || (cp2 > cp1))
- cp2 = cp1;
- else
- newperms = atoi (cp2+1);
- if(!strnicmp(file,cp,cp2 - cp)
- #ifdef MSDOS /* start past the X: drive letter */
- || !strnicmp(file+2,cp,cp2 - cp)
- #endif
- ) {
- perms = newperms;
- break;
- }
- if(*cp1 == '\0') return 0;
- }
- #endif
-
- #ifdef MSDOS
- /* Check for characters illegal in MS-DOS file names */
- for(cp = badchars;*cp != '\0';cp++){
- if(strchr(file,*cp) != NULLCHAR)
- return 0;
- }
- #endif
-
- switch(op){
- case RNFR_CMD:
- case RNTO_CMD:
- case RETR_CMD:
- /* User must have permission to read files */
- if(perms & FTP_READ)
- return 1;
- return 0;
- case DELE_CMD:
- case RMD_CMD:
- case RPUT_CMD:
- case APPE_CMD:
- /* User must have permission to (over)write files */
- if(perms & FTP_WRITE)
- return 1;
- return 0;
- case STOR_CMD:
- case MKD_CMD:
- /* User must have permission to (over)write files, or permission
- * to create them if the file doesn't already exist
- */
- if(perms & FTP_WRITE)
- return 1;
- if(access(file,2) == -1 && (perms & FTP_CREATE))
- return 1;
- return 0;
- }
- return 0; /* "can't happen" -- keep lint happy */
- }
- static int
- sendit(ftp,command,file)
- struct ftpserv *ftp;
- char *command;
- char *file;
- {
- long total, starting;
- unsigned long check;
- struct sockaddr_in dport;
- char *cp;
- char fsizetext[20]; /* N1BEE */
-
- fsizetext[0] = 0;
- ftp->data = socket(AF_INET,SOCK_STREAM,0);
- dport.sin_family = AF_INET;
- dport.sin_addr.s_addr = INADDR_ANY;
- dport.sin_port = IPPORT_FTPD;
- bind(ftp->data,(char *)&dport,SOCKSIZE);
- sprintf(fsizetext, "(%lu bytes)", filelength(fileno(ftp->fp)));
- usprintf(ftp->control,sending,command,file,fsizetext); /* N1BEE */
- if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
- fclose(ftp->fp);
- ftp->fp = NULLFILE;
- close_s(ftp->data);
- ftp->data = -1;
- usprintf(ftp->control,noconn);
- return -1;
- }
- if(strcmp(command,"RSME") == 0) {
- cp = mallocw(40);
- recvline(ftp->control,cp,40);
- starting = atol(cp);
- /* If checksum field is not present go on anyway, for compatibility
- * with previous scheme. If present check it and barf if wrong.
- */
- if(strchr(cp,' ') != NULL){
- check = (unsigned long)atol(strchr(cp,' '));
- check -= checksum(ftp->fp,starting);
- if(check != 0){
- free(cp);
- usprintf(ftp->control,badcheck);
- shutdown(ftp->data,1); /* Blow away data connection */
- goto send_err;
- }
- } else if(fseek(ftp->fp,starting,SEEK_SET) != 0) {
- free(cp);
- usprintf(ftp->control,noconn);
- shutdown(ftp->data,2); /* Blow away data connection */
- goto send_err;
- }
- }
-
- #ifdef FTPTDISC
- /* Turn off the timeout timer here, some ftp's could
- * take a long time with sloooow packet channels - WG7J
- */
- stop_timer(&ftp->tdisc);
- #endif
-
- #ifdef LZW
- if (ftp->lzw)
- lzwinit (ftp->data, ftp->lzwbits, ftp->lzwmode);
- #endif
-
- /* Do the actual transfer */
- total = sendfile(ftp->fp,ftp->data,ftp->type,0);
-
- #ifdef FTPTDISC
- /* And turn it back on now */
- start_timer(&ftp->tdisc);
- #endif
-
- if(total == -1){
- /* An error occurred on the data connection */
- usprintf(ftp->control,noconn);
- shutdown(ftp->data,2); /* Blow away data connection */
- } else {
- usprintf(ftp->control,txok);
- }
- send_err: fclose(ftp->fp);
- ftp->fp = NULLFILE;
- close_s(ftp->data);
- ftp->data = -1;
- if(total == -1)
- return -1;
- else
- return 0;
- }
- static int
- recvit(ftp,command,file)
- struct ftpserv *ftp;
- char *command;
- char *file;
- {
- struct sockaddr_in dport;
- long total, starting;
-
- ftp->data = socket(AF_INET,SOCK_STREAM,0);
- dport.sin_family = AF_INET;
- dport.sin_addr.s_addr = INADDR_ANY;
- dport.sin_port = IPPORT_FTPD;
- bind(ftp->data,(char *)&dport,SOCKSIZE);
- usprintf(ftp->control,sending,command,file,"");
-
- if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
- fclose(ftp->fp);
- ftp->fp = NULLFILE;
- close_s(ftp->data);
- ftp->data = -1;
- usprintf(ftp->control,noconn);
- return -1;
- }
- if (strcmp(command, "APPE") == 0)
- fseek(ftp->fp,0,SEEK_END);
- if(strcmp(command,"RPUT") == 0){
- if((starting = getsize(ftp->fp)) == -1)
- starting = 0L;
- usprintf(ftp->control,"%lu %lu\n",starting,checksum(ftp->fp,starting));
- fseek(ftp->fp,starting,SEEK_SET);
- }
-
- #ifdef FTPTDISC
- /* Turn of the timeout timer here; some ftp's could
- * take a long time with sloooow packet channels - WG7J
- */
- stop_timer(&ftp->tdisc);
- #endif
-
- #ifdef LZW
- if (ftp->lzw)
- lzwinit (ftp->data, ftp->lzwbits, ftp->lzwmode);
- #endif
-
- /* Do the actual transfer */
- total = recvfile(ftp->fp,ftp->data,ftp->type,0);
-
- #ifdef FTPTDISC
- /* And turn it back on now */
- start_timer(&ftp->tdisc);
- #endif
-
- #ifdef CPM
- if(ftp->type == ASCII_TYPE)
- putc(CTLZ,ftp->fp);
- #endif
- if(total == -1) {
- /* An error occurred while writing the file */
- usprintf(ftp->control,writerr,sys_errlist[errno]);
- shutdown(ftp->data,2); /* Blow it away */
- } else {
- usprintf(ftp->control,rxok);
- close_s(ftp->data);
- }
- ftp->data = -1;
- fclose(ftp->fp);
- ftp->fp = NULLFILE;
- if(total == -1)
- return -1;
- else
- return 0;
- }
-